home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 52 / Amiga Format AFCD52 (Issue 136, May 2000).iso / -in_the_mag- / workbench / adf / adflib / adflib.lha / Lib / adf_cache.c < prev    next >
C/C++ Source or Header  |  1999-05-22  |  17KB  |  596 lines

  1. /*
  2.  *  ADF Library. (C) 1997-1998 Laurent Clevy
  3.  *
  4.  *  adf_cache.c
  5.  *
  6.  */ 
  7.  
  8. #include<stdlib.h>
  9. #include<string.h>
  10.  
  11. #include"adf_defs.h"
  12. #include"adf_str.h"
  13. #include"adf_err.h"
  14. #include"defendian.h"
  15. #include"adf_cache.h"
  16. #include"adf_raw.h"
  17. #include"adf_disk.h"
  18. #include"adf_bitm.h"
  19. #include"adf_util.h"
  20. #include"adf_dir.h"
  21.  
  22.  
  23. extern struct Env adfEnv;
  24. /*
  25. freeEntCache(struct CacheEntry *cEntry)
  26. {
  27.     if (cEntry->name!=NULL)
  28.         free(cEntry->name);
  29.     if (cEntry->comm!=NULL)
  30.         free(cEntry->comm);
  31. }
  32. */
  33.  
  34. /*
  35.  * adfGetDirEntCache
  36.  *
  37.  * replace 'adfGetDirEnt'. returns a the dir contents based on the dircache list
  38.  */
  39. struct List* adfGetDirEntCache(struct Volume *vol, SECTNUM dir, BOOL recurs)
  40. {
  41.     struct bEntryBlock parent;
  42.     struct bDirCacheBlock dirc;
  43.     int offset, n;
  44.     struct List *cell, *head;
  45.     struct CacheEntry caEntry;
  46.     struct Entry *entry;
  47.     SECTNUM nSect;
  48.  
  49.     if (adfReadEntryBlock(vol,dir,&parent)!=RC_OK)
  50.         return NULL;
  51.  
  52.     nSect = parent.extension;
  53.  
  54.     cell = head = NULL;
  55.     do {
  56.         /* one loop per cache block */
  57.         n = offset = 0;
  58.         if (adfReadDirCBlock(vol, nSect, &dirc)!=RC_OK)
  59.             return NULL;
  60.         while (n<dirc.recordsNb) {
  61.             /* one loop per record */
  62.             entry = (struct Entry*)malloc(sizeof(struct Entry));
  63.             if (!entry) {
  64.                 adfFreeDirList(head);
  65.                 return NULL;
  66.             }
  67.             adfGetCacheEntry(&dirc, &offset, &caEntry);
  68.  
  69.             /* converts a cache entry into a dir entry */
  70.             entry->type = (int)caEntry.type;
  71.             entry->name = strdup(caEntry.name);
  72.             if (entry->name==NULL) {
  73.                 free(entry); adfFreeDirList(head);
  74.                 return NULL;
  75.             }
  76.             entry->sector = caEntry.header;
  77.             entry->comment = strdup(caEntry.comm);
  78.             if (entry->comment==NULL) {
  79.                 free(entry->name); adfFreeDirList(head);
  80.                 return NULL;
  81.             }
  82.             entry->size = caEntry.size;
  83.             entry->access = caEntry.protect;
  84.             adfDays2Date( caEntry.days, &(entry->year), &(entry->month), 
  85.                 &(entry->days) );
  86.             entry->hour = caEntry.mins/60;
  87.             entry->mins = caEntry.mins%60;
  88.             entry->secs = caEntry.ticks/50;
  89.  
  90.             /* add it into the linked list */
  91.             if (head==NULL)
  92.                 head = cell = newCell(NULL, (void*)entry); 
  93.             else
  94.                 cell = newCell(cell, (void*)entry); 
  95.  
  96.             if (cell==NULL) {
  97.                 adfFreeEntry(entry);
  98.                 adfFreeDirList(head);
  99.                 return NULL;
  100.             }
  101.  
  102.             if (recurs && entry->type==ST_DIR)
  103.                  cell->subdir = adfGetDirEntCache(vol,entry->sector,recurs);
  104.  
  105.             n++;
  106.         }
  107.         nSect = dirc.nextDirC;
  108.     }while (nSect!=0);
  109.     
  110.     return head;    
  111. }
  112.  
  113.  
  114.  
  115. /*
  116.  * adfGetCacheEntry
  117.  *
  118.  * Returns a cache entry, starting from the offset p (the index into records[])
  119.  * This offset is updated to the end of the returned entry.
  120.  */
  121. void adfGetCacheEntry(struct bDirCacheBlock *dirc, int *p, struct CacheEntry *cEntry)
  122. {
  123.     int ptr;
  124.  
  125.     ptr = *p;
  126.  
  127. //printf("p=%d\n",ptr);
  128.  
  129. #ifdef LITT_ENDIAN
  130.     cEntry->header = swapLong(dirc->records+ptr);
  131.     cEntry->size = swapLong(dirc->records+ptr+4);
  132.     cEntry->protect = swapLong(dirc->records+ptr+8);
  133.     cEntry->days = swapShort(dirc->records+ptr+16);
  134.     cEntry->mins = swapShort(dirc->records+ptr+18);
  135.     cEntry->ticks = swapShort(dirc->records+ptr+20);
  136. #else
  137.     cEntry->header = Long(dirc->records+ptr);
  138.     cEntry->size = Long(dirc->records+ptr+4);
  139.     cEntry->protect = Long(dirc->records+ptr+8);
  140.     cEntry->days = Short(dirc->records+ptr+16);
  141.     cEntry->mins = Short(dirc->records+ptr+18);
  142.     cEntry->ticks = Short(dirc->records+ptr+20);
  143. #endif
  144.     cEntry->type =(signed char) dirc->records[ptr+22];
  145.  
  146.     cEntry->nLen = dirc->records[ptr+23];
  147. /*    cEntry->name = (char*)malloc(sizeof(char)*(cEntry->nLen+1));
  148.     if (!cEntry->name)
  149.          return;
  150. */    memcpy(cEntry->name, dirc->records+ptr+24, cEntry->nLen);
  151.     cEntry->name[(int)(cEntry->nLen)]='\0';
  152.  
  153.     cEntry->cLen = dirc->records[ptr+24+cEntry->nLen];
  154.     if (cEntry->cLen>0) {
  155. /*        cEntry->comm =(char*)malloc(sizeof(char)*(cEntry->cLen+1));
  156.         if (!cEntry->comm) {
  157.             free( cEntry->name ); cEntry->name=NULL;
  158.             return;
  159.         }
  160. */        memcpy(cEntry->comm,dirc->records+ptr+24+cEntry->nLen+1,cEntry->cLen);
  161.     }
  162.         cEntry->comm[(int)(cEntry->cLen)]='\0';
  163. //printf("cEntry->nLen %d cEntry->cLen %d %s\n",cEntry->nLen,cEntry->cLen,cEntry->name);
  164.     *p  = ptr+24+cEntry->nLen+1+cEntry->cLen;
  165.  
  166.     /* the starting offset of each record must be even (68000 constraint) */ 
  167.     if ((*p%2)!=0)
  168.         *p=(*p)+1;
  169. }
  170.  
  171.  
  172. /*
  173.  * adfPutCacheEntry
  174.  *
  175.  * remplaces one cache entry at the p offset, and returns its length
  176.  */
  177. int adfPutCacheEntry( struct bDirCacheBlock *dirc, int *p, struct CacheEntry *cEntry)
  178. {
  179.     int ptr, l;
  180.  
  181.     ptr = *p;
  182.  
  183. #ifdef LITT_ENDIAN
  184.     swLong(dirc->records+ptr, cEntry->header);
  185.     swLong(dirc->records+ptr+4, cEntry->size);
  186.     swLong(dirc->records+ptr+8, cEntry->protect);
  187.     swShort(dirc->records+ptr+16, cEntry->days);
  188.     swShort(dirc->records+ptr+18, cEntry->mins);
  189.     swShort(dirc->records+ptr+20, cEntry->ticks);
  190. #else
  191.     memcpy(dirc->records+ptr,&(cEntry->header),4);
  192.     memcpy(dirc->records+ptr+4,&(cEntry->size),4);
  193.     memcpy(dirc->records+ptr+8,&(cEntry->protect),4);
  194.     memcpy(dirc->records+ptr+16,&(cEntry->days),2);
  195.     memcpy(dirc->records+ptr+18,&(cEntry->mins),2);
  196.     memcpy(dirc->records+ptr+20,&(cEntry->ticks),2);
  197. #endif
  198.     dirc->records[ptr+22] =(signed char)cEntry->type;
  199.  
  200.     dirc->records[ptr+23] = cEntry->nLen;
  201.     memcpy(dirc->records+ptr+24, cEntry->name, cEntry->nLen);
  202.  
  203.     dirc->records[ptr+24+cEntry->nLen] = cEntry->cLen;
  204.     memcpy(dirc->records+ptr+24+cEntry->nLen+1, cEntry->comm, cEntry->cLen);
  205.  
  206. //puts("adfPutCacheEntry");
  207.  
  208.     l = 25+cEntry->nLen+cEntry->cLen;
  209.     if ((l%2)==0)
  210.         return l;
  211.     else {
  212.         dirc->records[ptr+l] =(char)0;
  213.         return l+1;
  214.     }
  215.  
  216.     /* ptr%2 must be == 0, if l%2==0, (ptr+l)%2==0 */ 
  217. }
  218.  
  219.  
  220. /*
  221.  * adfEntry2CacheEntry
  222.  *
  223.  * converts one dir entry into a cache entry, and return its future length in records[]
  224.  */
  225. int adfEntry2CacheEntry(struct bEntryBlock *entry, struct CacheEntry *newEntry)
  226. {
  227.     int entryLen;
  228.  
  229.     /* new entry */
  230.     newEntry->header = entry->headerKey;
  231.     if (entry->secType==ST_FILE)
  232.         newEntry->size = entry->byteSize;
  233.     else
  234.         newEntry->size = 0L;
  235.     newEntry->protect = entry->access;
  236.     newEntry->days = (short)entry->days;
  237.     newEntry->mins = (short)entry->mins;
  238.     newEntry->ticks  = (short)entry->ticks;
  239.     newEntry->type = (signed char)entry->secType;
  240.     newEntry->nLen = entry->nameLen;
  241.     memcpy(newEntry->name, entry->name, newEntry->nLen);
  242.     newEntry->name[(int)(newEntry->nLen)] = '\0';
  243.     newEntry->cLen = entry->commLen;
  244.     if (newEntry->cLen>0)
  245.         memcpy(newEntry->comm, entry->comment, newEntry->cLen);
  246.  
  247.     entryLen = 24+newEntry->nLen+1+newEntry->cLen;
  248.  
  249. /*printf("entry->name %d entry->comment %d\n",entry->nameLen,entry->commLen);
  250. printf("newEntry->nLen %d newEntry->cLen %d\n",newEntry->nLen,newEntry->cLen);
  251. */    if ((entryLen%2)==0)
  252.         return entryLen;
  253.     else
  254.         return entryLen+1;
  255. }
  256.  
  257.  
  258. /*
  259.  * adfDelFromCache
  260.  *
  261.  * delete one cache entry from its block. don't do 'records garbage collecting'
  262.  */
  263. RETCODE adfDelFromCache(struct Volume *vol, struct bEntryBlock *parent, 
  264.     SECTNUM headerKey)
  265. {
  266.     struct bDirCacheBlock dirc;
  267.     SECTNUM nSect, prevSect;
  268.     struct CacheEntry caEntry;
  269.     int offset, oldOffset, n;
  270.     BOOL found;
  271.     int entryLen;
  272.     int i;
  273.     RETCODE rc = RC_OK;
  274.  
  275.     prevSect = -1;
  276.     nSect = parent->extension;
  277.     found = FALSE;
  278.     do {
  279.         adfReadDirCBlock(vol, nSect, &dirc);
  280.         offset = 0; n = 0;
  281.         while(n < dirc.recordsNb && !found) {
  282.             oldOffset = offset;
  283.             adfGetCacheEntry(&dirc, &offset, &caEntry);
  284.             found = (caEntry.header==headerKey);
  285.             if (found) {
  286.                 entryLen = offset-oldOffset;
  287.                 if (dirc.recordsNb>1 || prevSect==-1) {
  288.                     if (n<dirc.recordsNb-1) {
  289.                         /* not the last of the block : switch the following records */
  290.                         for(i=oldOffset; i<(488-entryLen); i++)
  291.                             dirc.records[i] = dirc.records[i+entryLen];
  292.                         /* and clear the following bytes */
  293.                         for(i=488-entryLen; i<488; i++)
  294.                             dirc.records[i] = 0;
  295.                     }
  296.                     else {
  297.                         /* the last record of this cache block */
  298.                         for(i=oldOffset; i<offset; i++)
  299.                             dirc.records[i] = 0;
  300.                     }
  301.                     dirc.recordsNb--;
  302.                     if (adfWriteDirCBlock(vol, dirc.headerKey, &dirc)!=RC_OK)
  303.                         return -1;
  304.                 }
  305.                 else {
  306.                     /* dirc.recordsNb ==1 or == 0 , prevSect!=-1 : 
  307.                     * the only record in this dirc block and a previous dirc block exists 
  308.                     */
  309.                     adfSetBlockFree(vol, dirc.headerKey);
  310.                     adfReadDirCBlock(vol, prevSect, &dirc);
  311.                     dirc.nextDirC = 0L;
  312.                     adfWriteDirCBlock(vol, prevSect, &dirc);
  313.  
  314.                     adfUpdateBitmap(vol);
  315.                 }
  316.             }
  317.             n++;
  318.         }
  319.         prevSect = nSect;
  320.         nSect = dirc.nextDirC;
  321.     }while(nSect!=0 && !found);
  322.  
  323.     if (!found)
  324.         (*adfEnv.wFct)("adfUpdateCache : entry not found");
  325.  
  326.     return rc;
  327. }
  328.  
  329.  
  330. /*
  331.  * adfAddInCache
  332.  *
  333.  */
  334. RETCODE adfAddInCache(struct Volume *vol, struct bEntryBlock *parent, 
  335.     struct bEntryBlock *entry)
  336. {
  337.     struct bDirCacheBlock dirc, newDirc;
  338.     SECTNUM nSect, nCache;
  339.     struct CacheEntry caEntry, newEntry;
  340.     int offset, n;
  341.     int entryLen;
  342.  
  343.     entryLen = adfEntry2CacheEntry(entry, &newEntry);
  344. /*printf("adfAddInCache--%4ld %2d %6ld %8lx %4d %2d:%02d:%02d %30s %22s\n",
  345.     newEntry.header, newEntry.type, newEntry.size, newEntry.protect,
  346.     newEntry.days, newEntry.mins/60, newEntry.mins%60, 
  347.     newEntry.ticks/50,
  348.     newEntry.name, newEntry.comm);
  349. */
  350.     nSect = parent->extension;
  351.     do {
  352.         if (adfReadDirCBlock(vol, nSect, &dirc)!=RC_OK)
  353.             return RC_ERROR;
  354.         offset = 0; n = 0;
  355. //printf("parent=%4ld\n",dirc.parent);
  356.         while(n < dirc.recordsNb) {
  357.             adfGetCacheEntry(&dirc, &offset, &caEntry);
  358. /*printf("*%4ld %2d %6ld %8lx %4d %2d:%02d:%02d %30s %22s\n",
  359.     caEntry.header, caEntry.type, caEntry.size, caEntry.protect,
  360.     caEntry.days, caEntry.mins/60, caEntry.mins%60, 
  361.     caEntry.ticks/50,
  362.     caEntry.name, caEntry.comm);
  363. */
  364.             n++;
  365.         }
  366.         
  367. /*        if (offset+entryLen<=488) {
  368.             adfPutCacheEntry(&dirc, &offset, &newEntry);
  369.             dirc.recordsNb++;
  370.             adfWriteDirCBlock(vol, dirc.headerKey, &dirc);
  371.             return rc;
  372.         }*/
  373.         nSect = dirc.nextDirC;
  374.     }while(nSect!=0);
  375.  
  376.     /* in the last block */
  377.     if (offset+entryLen<=488) {
  378.         adfPutCacheEntry(&dirc, &offset, &newEntry);
  379.         dirc.recordsNb++;
  380. //printf("entry name=%s\n",newEntry.name);
  381.     }
  382.     else {
  383.         /* request one new block free */
  384.         nCache = adfGet1FreeBlock(vol);
  385.         if (nCache==-1) {
  386.            (*adfEnv.wFct)("adfCreateDir : nCache==-1");
  387.            return RC_VOLFULL;
  388.         }
  389.  
  390.         /* create a new dircache block */
  391.         memset(&newDirc,0,512);
  392.         if (parent->secType==ST_ROOT)
  393.             newDirc.parent = vol->rootBlock;
  394.         else if (parent->secType==ST_DIR)
  395.             newDirc.parent = parent->headerKey;
  396.         else
  397.             (*adfEnv.wFct)("adfAddInCache : unknown secType");
  398.         newDirc.recordsNb = 0L;
  399.         newDirc.nextDirC = 0L;
  400.  
  401.         adfPutCacheEntry(&dirc, &offset, &newEntry);
  402.         newDirc.recordsNb++;
  403.         if (adfWriteDirCBlock(vol, nCache, &newDirc)!=RC_OK)
  404.             return RC_ERROR;
  405.         dirc.nextDirC = nCache;
  406.     }
  407. //printf("dirc.headerKey=%ld\n",dirc.headerKey);
  408.     if (adfWriteDirCBlock(vol, dirc.headerKey, &dirc)!=RC_OK)
  409.         return RC_ERROR;
  410. /*if (strcmp(entry->name,"file_5u")==0)
  411. dumpBlock(&dirc);
  412. */
  413.     return RC_OK;
  414. }
  415.  
  416.  
  417. /*
  418.  * adfUpdateCache
  419.  *
  420.  */
  421. RETCODE adfUpdateCache(struct Volume *vol, struct bEntryBlock *parent, 
  422.     struct bEntryBlock *entry, BOOL entryLenChg)
  423. {
  424.     struct bDirCacheBlock dirc;
  425.     SECTNUM nSect;
  426.     struct CacheEntry caEntry, newEntry;
  427.     int offset, oldOffset, n;
  428.     BOOL found;
  429.     int i, oLen, nLen;
  430.     int sLen; /* shift length */
  431.  
  432.     nLen = adfEntry2CacheEntry(entry, &newEntry);
  433.  
  434.     nSect = parent->extension;
  435.     found = FALSE;
  436.     do {
  437. //printf("dirc=%ld\n",nSect);
  438.         if (adfReadDirCBlock(vol, nSect, &dirc)!=RC_OK)
  439.             return RC_ERROR;
  440.         offset = 0; n = 0;
  441.         /* search entry to update with its header_key */
  442.         while(n < dirc.recordsNb && !found) {
  443.             oldOffset = offset;
  444.             /* offset is updated */
  445.             adfGetCacheEntry(&dirc, &offset, &caEntry);
  446.             oLen = offset-oldOffset;
  447.             sLen = oLen-nLen;
  448. //printf("olen=%d nlen=%d\n",oLen,nLen);
  449.             found = (caEntry.header==newEntry.header);
  450.             if (found) {
  451.                 if (!entryLenChg || oLen==nLen) {
  452.                     /* same length : remplace the old values */
  453.                     adfPutCacheEntry(&dirc, &oldOffset, &newEntry);
  454. //if (entryLenChg) puts("oLen==nLen");
  455.                     if (adfWriteDirCBlock(vol, dirc.headerKey, &dirc)!=RC_OK)
  456.                         return RC_ERROR;
  457.                 }
  458.                 else if (oLen>nLen) {
  459. //puts("oLen>nLen");
  460.                     /* the new record is shorter, write it, 
  461.                      * then shift down the following records 
  462.                      */
  463.                     adfPutCacheEntry(&dirc, &oldOffset, &newEntry);
  464.                     for(i=oldOffset+nLen; i<(488-sLen); i++)
  465.                         dirc.records[i] = dirc.records[i+sLen];
  466.                     /* then clear the following bytes */
  467.                     for(i=488-sLen; i<488; i++)
  468.                         dirc.records[i] = (char)0;
  469.  
  470.                     if (adfWriteDirCBlock(vol, dirc.headerKey, &dirc)!=RC_OK)
  471.                         return RC_ERROR;
  472.                 }
  473.                 else {
  474.                     /* the new record is larger */
  475. //puts("oLen<nLen");
  476.                     adfDelFromCache(vol,parent,entry->headerKey);
  477.                     adfAddInCache(vol,parent,entry);
  478. //puts("oLen<nLen end");
  479.  
  480.                 }
  481.             }
  482.             n++;
  483.         }
  484.         nSect = dirc.nextDirC;
  485.     }while(nSect!=0 && !found);
  486.  
  487.     if (found) {
  488.         if (adfUpdateBitmap(vol)!=RC_OK)
  489.             return RC_ERROR;
  490.     }
  491.     else
  492.         (*adfEnv.wFct)("adfUpdateCache : entry not found");
  493.  
  494.     return RC_OK;
  495. }
  496.  
  497.  
  498. /*
  499.  * adfCreateEmptyCache
  500.  *
  501.  */
  502. RETCODE adfCreateEmptyCache(struct Volume *vol, struct bEntryBlock *parent, SECTNUM nSect)
  503. {
  504.     struct bDirCacheBlock dirc;
  505.     SECTNUM nCache;
  506.  
  507.     if (nSect==-1) {
  508.         nCache = adfGet1FreeBlock(vol);
  509.         if (nCache==-1) {
  510.            (*adfEnv.wFct)("adfCreateDir : nCache==-1");
  511.            return RC_VOLFULL;
  512.         }
  513.     }
  514.     else
  515.         nCache = nSect;
  516.  
  517.     if (parent->extension==0)
  518.         parent->extension = nCache;
  519.  
  520.     memset(&dirc,0, sizeof(struct bDirCacheBlock));
  521.  
  522.     if (parent->secType==ST_ROOT)
  523.         dirc.parent = vol->rootBlock;
  524.     else if (parent->secType==ST_DIR)
  525.         dirc.parent = parent->headerKey;
  526.     else {
  527.         (*adfEnv.wFct)("adfCreateEmptyCache : unknown secType");
  528. //printf("secType=%ld\n",parent->secType);
  529.     }
  530.         
  531.     dirc.recordsNb = 0;
  532.     dirc.nextDirC = 0;
  533.  
  534.     if (adfWriteDirCBlock(vol, nCache, &dirc)!=RC_OK)
  535.         return RC_ERROR;
  536.  
  537.     return RC_OK;
  538. }
  539.  
  540.  
  541. /*
  542.  * adfReadDirCBlock
  543.  *
  544.  */
  545. RETCODE adfReadDirCBlock(struct Volume *vol, SECTNUM nSect, struct bDirCacheBlock *dirc)
  546. {
  547.     unsigned char buf[512];
  548.  
  549.     if (adfReadBlock(vol, nSect, buf)!=RC_OK)
  550.         return RC_ERROR;
  551.  
  552.     memcpy(dirc,buf,512);
  553. #ifdef LITT_ENDIAN
  554.     swapEndian((unsigned char*)dirc,SWBL_CACHE);
  555. #endif
  556.     if (dirc->checkSum!=adfNormalSum(buf,20,512))
  557.         (*adfEnv.wFct)("adfReadDirCBlock : invalid checksum");
  558.     if (dirc->type!=T_DIRC)
  559.         (*adfEnv.wFct)("adfReadDirCBlock : T_DIRC not found");
  560.     if (dirc->headerKey!=nSect)
  561.         (*adfEnv.wFct)("adfReadDirCBlock : headerKey!=nSect");
  562.  
  563.     return RC_OK;
  564. }
  565.  
  566.  
  567. /*
  568.  * adfWriteDirCblock
  569.  *
  570.  */
  571. RETCODE adfWriteDirCBlock(struct Volume* vol, long nSect, struct bDirCacheBlock* dirc)
  572. {
  573.     unsigned char buf[LOGICAL_BLOCK_SIZE];
  574.     unsigned long newSum;
  575.  
  576.     dirc->type = T_DIRC;
  577.     dirc->headerKey = nSect; 
  578.  
  579.     memcpy(buf, dirc, LOGICAL_BLOCK_SIZE);
  580. #ifdef LITT_ENDIAN
  581.     swapEndian(buf, SWBL_CACHE);
  582. #endif
  583.  
  584.     newSum = adfNormalSum(buf, 20, LOGICAL_BLOCK_SIZE);
  585.     swLong(buf+20,newSum);
  586. //    *(long*)(buf+20) = swapLong((unsigned char*)&newSum);
  587.  
  588.     if (adfWriteBlock(vol, nSect, buf)!=RC_OK)
  589.         return RC_ERROR;
  590. //puts("adfWriteDirCBlock");
  591.  
  592.     return RC_OK;
  593. }
  594.  
  595. /*################################################################################*/
  596.